//
// kinit.cpp
// Usage: Kernel initialize routine
// Create Date: 2009-03-06
// Author: MaJiuyue
//
#include <NewLife.h>
#include <string.h>
#include "bootutil.h"
#include "SCI.h"
#include "../core/ResourceManager.h"
#include "../pageman/PageFrameAllocator.h"
#include "../intrman/ActionManager.h"
#include "../intrman/DefaultIRQAction.h"
#include "../intrman/IntrGateManager.h"
#include "../intrman/ClockIRQAction.h"
#include "../pageman/PageTable.h"
#include "../pageman/PageFaultAction.h"
#include "../schedule/Process.h"
#include "../schedule/ProcessManager.h"
#include "../schedule/Scheduler.h"
#include "../moduleman/ModuleManager.h"
#include "../fs/VFS.h"
#include "../ipc/IPCCenter.h"

void InitializeTSS()
{
	// Initialize global var `tss'
	memset(&tss, 0, sizeof(tss));
	tss.ss0 = SELECTOR_KERNEL_RW;
	tss.iobase = (u32)tss.io_bitmap - (u32)&tss;

	// Load tr register
	__asm__ __volatile__("ltr %%ax"::"a"(SELECTOR_TSS));
}

extern "C"
void kinit()
{
	// Initialize TaskStatusSegment
	InitializeTSS();

	// Create all core resource
	Callable * target = NULL;
	Resource * res = NULL;

	target = new CPageFrameAllocator(PHYMAP_END/PAGE_SIZE);
	target = new CActionManager();
	target = new CIntrGateManager();
	target = new CModuleManager(mods_addr, mods_count);
	target = new CProcessManager();
	target = new CScheduler();
	target = new VFS();
	target = new CIPCCenter();

	// Get ActionManager resource
	res = ResourceManager.RequestResource(
		ServiceCallInterface::ActionManager::ResourceName
	);

	// Register #PF exception action as PageFaultAction
	res->CallSCI(
		ServiceCallInterface::ActionManager::SCIID_RegisterExAction,
		VECTOR_PAGEFAULT,
		(u32)(ExceptionAction *)PageFaultAction::GetInstance()
	);

	// Register Clock IRQ's (IRQ0) action as ClockIRQAction
	res->CallSCI(
		ServiceCallInterface::ActionManager::SCIID_RegisterIRQAction, 
		CLOCK_IRQ,
		(u32)(IRQAction *)ClockIRQAction::GetInstance()
	);

	// Enable Clock IRQ
	res = ResourceManager.RequestResource(
		ServiceCallInterface::IntrGateManager::ResourceName
	);
	res->CallSCI(
		ServiceCallInterface::IntrGateManager::SCIID_EnableIRQ, 
		CLOCK_IRQ	
	);


/**************************** FS Test **********************************/
/*
	res = ResourceManager.RequestResource(
		ServiceCallInterface::FileSystem::ResourceName
	);
	Directory * root = (Directory *)res->CallSCI(
		ServiceCallInterface::FileSystem::SCIID_GetRoot
	);

	kprintf("Read root fs......[%d]\n", root->GetEntryCount());
	for(int i=0; i<root->GetEntryCount(); i++)
	{
		File * entry = root->GetEntry(i);
		kprintf("%s\n", entry->GetFileName());

		if((entry->GetType()==FT_DIRECTORY) && (((Directory*)entry)->GetEntryCount()>0))
		{
			kprintf("\t");
			for(int j=0;j<((Directory*)entry)->GetEntryCount();j++)
				kprintf("%s  ", ((Directory*)entry)->GetEntry(j)->GetFileName());
			kprintf("\n");
		}

	}
	kprintf("\n\n");
*/
/***********************************************************************/

	// Create process for module
	res = ResourceManager.RequestResource(
		ServiceCallInterface::ModuleManager::ResourceName
	);

	int mod_count = res->CallSCI(
		ServiceCallInterface::ModuleManager::SCIID_GetModuleCount
	);
	kprintf("Get start module...............Total[%d]\n", mod_count);
	// Foreach module	
	for(int i=0; i<mod_count; i++)
	{
		Module * mod = (Module *)res->CallSCI(
		    ServiceCallInterface::ModuleManager::SCIID_GetModuleByIndex,
		    i 
		);
		kprintf("Create process \"%s\"........", mod->GetModuleName());
		Process * p = mod->CreateProcess();
		kprintf("[OK][%d]\n", p->GetPID());
	}

	kprintf("Restarting process[0]........");

	// Restart user process
	res = ResourceManager.RequestResource(ServiceCallInterface::ProcessManager::ResourceName);
	Process * proc = (Process *)res->CallSCI(
		ServiceCallInterface::ProcessManager::SCIID_GetProcessByPid, 
		0
	);
	
	kprintf("[OK]\n");
	proc->GetThread()->Restart();
}

